"""
LSP 集成包装器

为主混淆流程提供 LSP 重命名功能，支持回退到 AST。
"""

from pathlib import Path
from typing import Dict, Optional, List
from dataclasses import dataclass

from core.builtin_config_module.builtin_config import BuiltInConfig
from core.lsp_module.lsp_renamer import LSPRenamer
from core.utils_module.logger import ObfuscationLogger


@dataclass
class LSPIntegrationResult:
    """LSP 集成结果"""
    success: bool
    renamed_count: int = 0
    failed_count: int = 0
    lsp_used: int = 0  # LSP 成功的次数
    ast_fallback: int = 0  # AST 回退的次数
    errors: List[str] = None
    warnings: List[str] = None

    def __post_init__(self):
        if self.errors is None:
            self.errors = []
        if self.warnings is None:
            self.warnings = []


class LSPIntegration:
    """
    LSP 集成包装器

    提供混淆器使用 LSP 进行符号重命名的功能:
    - 自动启用/禁用 LSP
    - 回退机制 (LSP → AST → 正则)
    - 结果聚合和报告
    """

    def __init__(self, config: BuiltInConfig, logger: ObfuscationLogger):
        """
        初始化 LSP 集成

        Args:
            config: 统一配置对象
            logger: 日志记录器
        """
        self.config = config
        self.logger = logger
        self.lsp_enabled = config.advanced_features.lsp_enabled
        self.lsp_renamer: Optional[LSPRenamer] = None

        # 如果启用 LSP，创建 renamer
        if self.lsp_enabled:
            try:
                self.lsp_renamer = LSPRenamer(config.project_path)
                self.logger.log_operation("LSP", "LSP 重命名器已启用")
            except Exception as e:
                self.logger.log_operation("LSP", f"LSP 初始化失败: {e}")
                self.lsp_enabled = False

    def rename_symbols(
        self,
        symbol_map: Dict[str, str],
        fallback_renamer=None
    ) -> LSPIntegrationResult:
        """
        使用 LSP 重命名符号，失败时回退

        Args:
            symbol_map: 符号映射 {old_name: new_name}
            fallback_renamer: 回退重命名器（通常是 AST 或正则）

        Returns:
            LSPIntegrationResult: 重命名结果
        """
        result = LSPIntegrationResult(success=False)

        # 如果 LSP 未启用，直接使用回退
        if not self.lsp_enabled or not self.lsp_renamer:
            if fallback_renamer:
                self.logger.log_operation("LSP", "LSP 未启用，使用回退重命名器")
                return self._use_fallback(symbol_map, fallback_renamer, result)
            else:
                result.errors.append("LSP 未启用且无回退重命名器")
                return result

        # 使用 LSP 重命名
        self.logger.log_operation("LSP", f"使用 LSP 重命名 {len(symbol_map)} 个符号")

        try:
            # 设置回退重命名器
            self.lsp_renamer.fallback_renamer = fallback_renamer

            # 执行重命名
            lsp_result = self.lsp_renamer.rename_symbols(symbol_map)

            # 汇总结果
            result.renamed_count = lsp_result.renamed_symbols
            result.failed_count = lsp_result.failed_symbols
            result.success = lsp_result.success
            result.errors.extend(lsp_result.errors)
            result.warnings.extend(lsp_result.warnings)

            # 统计 LSP vs 回退
            # 通过警告消息判断是否使用了回退
            for warning in lsp_result.warnings:
                if "使用回退重命名" in warning or "回退" in warning:
                    result.ast_fallback += 1
                else:
                    result.lsp_used += 1

            # 如果没有明确的回退标记，假设成功的都是 LSP
            if result.lsp_used == 0 and result.renamed_count > 0:
                result.lsp_used = result.renamed_count

            self.logger.log_operation(
                "LSP",
                f"LSP 重命名完成: 成功={result.renamed_count}, "
                f"失败={result.failed_count}, "
                f"LSP={result.lsp_used}, 回退={result.ast_fallback}"
            )

        except Exception as e:
            self.logger.log_operation("LSP", f"LSP 重命名异常: {e}")
            result.errors.append(f"LSP 异常: {str(e)}")

            # 如果配置允许，尝试回退
            if self.config.advanced_features.lsp_fallback_to_ast and fallback_renamer:
                self.logger.log_operation("LSP", "尝试使用回退重命名器")
                return self._use_fallback(symbol_map, fallback_renamer, result)

        return result

    def rename_symbol_in_file(
        self,
        file_path: str,
        old_name: str,
        new_name: str,
        fallback_renamer=None
    ) -> LSPIntegrationResult:
        """
        在单个文件中重命名符号

        Args:
            file_path: 文件路径
            old_name: 旧名称
            new_name: 新名称
            fallback_renamer: 回退重命名器

        Returns:
            LSPIntegrationResult
        """
        result = LSPIntegrationResult(success=False)

        if not self.lsp_enabled or not self.lsp_renamer:
            if fallback_renamer:
                return self._use_fallback({old_name: new_name}, fallback_renamer, result)
            else:
                result.errors.append("LSP 未启用且无回退重命名器")
                return result

        try:
            # 设置回退
            self.lsp_renamer.fallback_renamer = fallback_renamer

            # 执行重命名
            lsp_result = self.lsp_renamer.rename_symbol_in_file(
                file_path, old_name, new_name
            )

            # 汇总结果
            result.renamed_count = lsp_result.renamed_symbols
            result.failed_count = lsp_result.failed_symbols
            result.success = lsp_result.success
            result.errors.extend(lsp_result.errors)
            result.warnings.extend(lsp_result.warnings)

            # 统计
            for warning in lsp_result.warnings:
                if "使用回退" in warning:
                    result.ast_fallback += 1
                else:
                    result.lsp_used += 1

        except Exception as e:
            self.logger.log_operation("LSP", f"LSP 重命名异常: {e}")
            result.errors.append(f"LSP 异常: {str(e)}")

            if self.config.advanced_features.lsp_fallback_to_ast and fallback_renamer:
                return self._use_fallback({old_name: new_name}, fallback_renamer, result)

        return result

    def _use_fallback(
        self,
        symbol_map: Dict[str, str],
        fallback_renamer,
        result: LSPIntegrationResult
    ) -> LSPIntegrationResult:
        """
        使用回退重命名器

        Args:
            symbol_map: 符号映射
            fallback_renamer: 回退重命名器
            result: 结果对象（会被修改）

        Returns:
            更新后的 LSPIntegrationResult
        """
        try:
            # 调用回退重命名器
            # 注意: fallback_renamer 的接口可能不同，这里假设是通用接口
            for old_name, new_name in symbol_map.items():
                try:
                    # 假设 fallback_renamer 有 rename 方法
                    if hasattr(fallback_renamer, 'rename'):
                        try:
                            success = fallback_renamer.rename(old_name, new_name)
                        except TypeError:
                            try:
                                success = fallback_renamer.rename(None, old_name, new_name)
                            except TypeError:
                                result.warnings.append(f"回退重命名器参数不兼容: {old_name}")
                                result.failed_count += 1
                                continue
                        if success:
                            result.renamed_count += 1
                            result.ast_fallback += 1
                        else:
                            result.failed_count += 1
                    else:
                        result.warnings.append(f"回退重命名器接口不兼容: {old_name}")
                        result.failed_count += 1
                except Exception as e:
                    result.errors.append(f"回退失败 {old_name}: {str(e)}")
                    result.failed_count += 1

            result.success = result.renamed_count > 0

        except Exception as e:
            result.errors.append(f"回退重命名器异常: {str(e)}")

        return result

    def is_available(self) -> bool:
        """
        检查 LSP 是否可用

        Returns:
            是否可用
        """
        return self.lsp_enabled and self.lsp_renamer is not None

    def get_statistics(self) -> Dict:
        """
        获取统计信息

        Returns:
            统计字典
        """
        return {
            'lsp_enabled': self.lsp_enabled,
            'lsp_available': self.is_available(),
        }

    def cleanup(self):
        """清理 LSP 资源"""
        if self.lsp_renamer:
            try:
                self.lsp_renamer.cleanup()
                self.logger.log_operation("LSP", "LSP 资源已清理")
            except Exception as e:
                self.logger.log_operation("LSP", f"LSP 清理失败: {e}")

    def __enter__(self):
        """上下文管理器入口"""
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器退出"""
        self.cleanup()
